package com.mlnx.ui.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.mlnx.common.form.PageForm;
import com.mlnx.common.utils.ThreadUtil;
import com.mlnx.device.dao.mysql.DeviceMapper;
import com.mlnx.device.service.EcgDeviceService;
import com.mlnx.device.util.SortUtil;
import com.mlnx.service.base.service.BaseService;
import com.mlnx.service.common.enums.ResponseEnum;
import com.mlnx.service.common.exception.MutilDeviceServiceException;
import com.mlnx.ui.dao.GroupMapper;
import com.mlnx.ui.dao.PatientAlarmMapper;
import com.mlnx.ui.dao.PatientGroupMapper;
import com.mlnx.ui.dao.PatientMapper;
import com.mlnx.ui.entity.Group;
import com.mlnx.ui.entity.Patient;
import com.mlnx.ui.entity.PatientAlarm;
import com.mlnx.ui.entity.PatientGroup;
import com.mlnx.ui.pojo.dto.GroupDTO;
import com.mlnx.ui.pojo.dto.PatientAlarmDTO;
import com.mlnx.ui.pojo.dto.PatientDeviceDTO;
import com.mlnx.ui.pojo.form.*;
import com.mlnx.ui.pojo.vo.PatientVO;
import com.mlnx.ui.service.PatientService;
import com.mlnx.ui.util.HttpUtil;
import com.mlnx.ui.util.IDUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class PatientServiceImpl extends BaseService<PatientMapper, Patient> implements PatientService {
    @Autowired
    @Override
    public void setBaseMapper(PatientMapper baseMapper) {
        super.setBaseMapper(baseMapper);
    }

    @Autowired
    private PatientGroupMapper patientGroupMapper;
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private GroupMapper groupMapper;
    @Autowired
    private EcgDeviceService ecgDeviceService;
    @Autowired
    private PatientAlarmMapper patientAlarmMapper;

    @Override
    @Transactional
    public Integer addPatient(PatientForm patientForm) {
        Patient patient = new Patient();
        BeanUtils.copyProperties(patientForm, patient);

        if (patient.getIdentity().contains("-"))
            patient.setIdentity("000000" + patient.getIdentity().replace("-", "")
                    + "0000");
        patient.setUuid(IDUtils.createUUID());
        patient.setSource(0);

        save(patient);

        PatientGroup patientGroup = new PatientGroup();
        patientGroup.setGroupId(patientForm.getGroupId());
        patientGroup.setPatientId(patient.getId());

        try {
            patientGroupMapper.insert(patientGroup);
        } catch (Exception e) {
            e.printStackTrace();
            throw new MutilDeviceServiceException(ResponseEnum.ServerError);
        }

        return patient.getId();
    }

    @Override
    public Map<String, Object> getAllPatients(Integer userId, boolean taizhou) {
        List<Group> groupList = groupMapper.selectList(new QueryWrapper<Group>().eq("user_id", userId));
        Collection<String> onlineEcgDevices = ecgDeviceService.getOnlineEcgDeviceNums();

        Map<String, Object> resultMap = new HashMap<>();
        List<PatientAlarmDTO> patientAlarmDTOList;
        for (Group group : groupList) {
            Map<String, Object> paramMap = new HashMap<>();
            paramMap.put("groupId", group.getId());
            paramMap.put("taizhou", taizhou);

            patientAlarmDTOList = baseMapper.getPatientDetailsByGroupId(paramMap);

            for (PatientAlarmDTO patientAlarmDTO : patientAlarmDTOList) {
                patientAlarmDTO.setState(0);
                if (patientAlarmDTO.getNum() != null) {
                    for (String deviceId : onlineEcgDevices) {
                        if (deviceId.equals(patientAlarmDTO.getNum())) {
                            patientAlarmDTO.setState(1);
                            break;
                        }
                    }
                }
            }

            String groupId = Integer.toString(group.getId());
            resultMap.put(groupId, patientAlarmDTOList);
        }

        return resultMap;
    }

    @Override
    public List<Patient> getTaizhouPatients(Integer userId) {
        return baseMapper.selectAllPatientsByUserId(userId);
    }

    @Override
    public void movePatientsToGroup(Integer groupId, Integer[] patientIds) {
        Map<String, Object> paramMap = new HashMap();
        paramMap.put("groupId", groupId);
        paramMap.put("patientIds", patientIds);

        patientGroupMapper.batchUpdateGroupId(paramMap);
    }

    @Override
    @Transactional
    public void deletePatients(Integer[] patientIds) {
        baseMapper.batchUpdateAlive(patientIds);

        try {
            deviceMapper.batchUpdatePatientId(patientIds);
        } catch (Exception e) {
            e.printStackTrace();
            throw new MutilDeviceServiceException(ResponseEnum.ServerError);
        }

        try {
            patientGroupMapper.batchRemove(patientIds);
        } catch (Exception e) {
            e.printStackTrace();
            throw new MutilDeviceServiceException(ResponseEnum.ServerError);
        }
    }

    @Override
    public Integer getGroupPatientsCount(Integer groupId) {
        return patientGroupMapper.selectPatientsCountByGroupId(groupId);
    }

    @Override
    @Transactional
    public void synXKPatients(XKParamForm xkParamForm) throws MutilDeviceServiceException {
        String xkUrl = "http://" + xkParamForm.getIpAddress() + ":" + xkParamForm.getPort()
                + "/api/patientmls/List?access_token=" + xkParamForm.getToken();
        String result = HttpUtil.sendPost(xkUrl, "page=1&rows=8000&q=");

        JSONObject jsonObject = JSON.parseObject(result);
        JSONObject results = jsonObject.getJSONObject("results");
        JSONArray rows = results.getJSONArray("rows");

        if (rows == null || rows.size() <= 0)
            return;

        List<String> xkUUIDList = new ArrayList<>();
        for (int i = 0; i < rows.size(); i++) {
            JSONObject xkPatient = rows.getJSONObject(i);
            String xkUUID = xkPatient.getString("userid");

            xkUUIDList.add(xkUUID);
        }

        //查找并剔除已同步过的患者
        //注：已删除的患者无法通过同步找回
        List<Patient> existedUUIDList = baseMapper.selectExistedUUIDs(xkUUIDList);
        List<String> existedUUIDs = existedUUIDList.stream().map(Patient::getUuid).collect(Collectors.toList());
        xkUUIDList.removeAll(existedUUIDs);

//        if (xkUUIDList.size() <= 0)
//            return;

        List<Patient> patientList = new ArrayList<>();
        List<Patient> existedPatients = new ArrayList<>();
        for (int i = 0; i < rows.size(); i++) {
            JSONObject xkPatient = rows.getJSONObject(i);
            String xkUUID = xkPatient.getString("userid");

            for (Patient patient : existedUUIDList) {
                patient.setAlive(1);

                if (patient.getUuid().equals(xkUUID)) {
                    if (xkPatient.getString("telephone") != null)
                        patient.setPhone(xkPatient.getString("telephone"));
                    try {
                        patient.setName(new String(xkPatient.getString(
                                "realName").getBytes("utf-8"), "utf-8"));
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                    String identity;
                    if (xkPatient.getString("birthday") != null) {
                        String birthday = xkPatient.getString("birthday").substring(0,
                                10);
                        identity = "000000" + birthday.replace("-", "")
                                + "0000";

                    } else
                        identity = "000000200704300000";

                    patient.setIdentity(identity);

                    if (xkPatient.getString("gender") != null) {
                        if (xkPatient.getString("gender").equals("false"))
                            patient.setSex("F");
                        else
                            patient.setSex("M");
                    } else
                        patient.setSex("M");

                    patient.setSource(1);

                    existedPatients.add(patient);
                    break;
                }
            }

            for (String uuid : xkUUIDList) {
                if (uuid.equals(xkUUID)) {
                    Patient patient = new Patient();

                    if (xkPatient.getString("telephone") != null)
                        patient.setPhone(xkPatient.getString("telephone"));

                    try {
                        patient.setName(new String(xkPatient.getString(
                                "realName").getBytes("utf-8"), "utf-8"));
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }

                    String identity;
                    if (xkPatient.getString("birthday") != null) {
                        String birthday = xkPatient.getString("birthday").substring(0,
                                10);
                        identity = "000000" + birthday.replace("-", "")
                                + "0000";

                    } else
                        identity = "000000200704300000";

                    patient.setIdentity(identity);

                    if (xkPatient.getString("gender") != null) {
                        if (xkPatient.getString("gender").equals("false"))
                            patient.setSex("F");
                        else
                            patient.setSex("M");
                    } else
                        patient.setSex("M");

                    patient.setUuid(uuid);
                    patient.setSource(1);

                    patientList.add(patient);
                    break;
                }
            }
        }

        if (existedPatients.size() > 0) {
            ThreadUtil.execute(new Runnable() {
                @Override
                public void run() {
                    updateBatch(Patient.class, existedPatients, null);
                }
            });
        }

        if (patientList.size() > 0) {
            saveBatch(Patient.class, patientList);
            Integer groupId;

            Map<String, Object> paramMap = new HashMap();
            paramMap.put("userId", xkParamForm.getUserId());
            paramMap.put("taizhou", false);

            List<GroupDTO> groupDTOS = groupMapper.selectGroupsByUserId(paramMap);
            if (groupDTOS.size() > 0) {
                groupId = groupDTOS.get(0).getId();
            } else {
                Group group = new Group();
                group.setUserId(xkParamForm.getUserId());
                group.setName("默认群组");

                try {
                    groupMapper.insert(group);
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new MutilDeviceServiceException(ResponseEnum.ServerError);
                }

                groupId = group.getId();
            }


            List<Integer> patientIds = patientList.stream().map(Patient::getId).collect(Collectors.toList());
            paramMap = new HashMap<>();
            paramMap.put("groupId", groupId);
            paramMap.put("patientIds", patientIds);

            try {
                patientGroupMapper.batchInsert(paramMap);
            } catch (Exception e) {
                e.printStackTrace();
                throw new MutilDeviceServiceException(ResponseEnum.ServerError);
            }
        }
    }

    @Override
    public void setPatientAlarm(PatientAlarmForm patientAlarmForm) {
        patientAlarmMapper.updateInsert(patientAlarmForm);
    }

    @Override
    public List<PatientDeviceDTO> getPatientsByGroupId(Integer groupId) {
        Collection<String> onlineEcgDevices = ecgDeviceService.getOnlineEcgDeviceNums();
        List<PatientDeviceDTO> patientDeviceDTOList = baseMapper.selectPatientsByGroupId(groupId);

        for (PatientDeviceDTO patientDeviceDTO : patientDeviceDTOList) {
            patientDeviceDTO.setState(0);
            if (patientDeviceDTO.getNum() != null) {
                for (String device : onlineEcgDevices) {
                    if (device.equals(patientDeviceDTO.getNum())) {
                        patientDeviceDTO.setState(1);
                        break;
                    }
                }
            }
        }

        return patientDeviceDTOList;
    }

    @Override
    public PatientAlarmDTO getPatientDeviceInfo(Integer patientId) {
        Patient patient = getById(patientId);
        if (patient != null) {
            PatientAlarmDTO patientAlarmDTO = baseMapper.getPatientDeviceInfo(patientId);
            Collection<String> onlineEcgDevices = ecgDeviceService.getOnlineEcgDeviceNums();
            patientAlarmDTO.setState(0);
            for (String onlineEcgDevice : onlineEcgDevices) {
                if (onlineEcgDevice.equals(patientAlarmDTO.getNum())) {
                    patientAlarmDTO.setState(1);
                    break;
                }
            }

            return patientAlarmDTO;
        }
        return null;
    }

    @Override
    public PatientAlarmDTO getPatientDeviceInfo(String phone) {
        Patient patient = getOne(new QueryWrapper<Patient>().eq("phone", phone));
        if (patient != null) {
            PatientAlarmDTO patientAlarmDTO = baseMapper.getPatientDeviceInfo(patient.getId());
            return patientAlarmDTO;
        }
        return null;
    }

    @Override
    public Page<PatientVO> list(PageForm pageForm, PatientFilterForm patientFilterForm) {
        Page<PatientVO> patientVOPage = baseMapper.selectPatientPage(new Page<PatientVO>(pageForm.getCurrent(),
                pageForm.getSize()), patientFilterForm, SortUtil.parseSorter(patientFilterForm.getSorter()));

        return patientVOPage;
    }

    @Override
    public void updatePatient(Integer id, EditPatientForm editPatientForm) {
        Patient patient = new Patient();
        try {
            PropertyUtils.copyProperties(patient, editPatientForm);
        } catch (Exception e) {
            e.printStackTrace();
        }
        patient.setId(id);

        updateById(patient);
    }

    @Override
    public PatientAlarm getPatientAlarm(Integer patientId) {
        return patientAlarmMapper.selectById(patientId);
    }
}
